﻿function PerformanceCalculatorInterface() {

    this.startTime = 0;
    this.freezeTime = 0;

    this.onAction = function (time, action, mc) {
        if (action == enumAction.MAINTENANCE || action == enumAction.MALFUNCTION_OCCUR) {
            this.startTime = time;
            this.freezeTime = 0;
        }
        
        if (action == enumAction.SHUTDOWN || action == enumAction.COLISSION) {
            this.onCollisionOrShutdown(time, action, mc);
        }
    }

    this.onCollisionOrShutdown = function (time, action) {

    }

    this.onSpaceshipFreeze = function (time, freezeDuration) {
        this.freezeTime += freezeDuration;
        this._onSpaceshipFreeze(time, freezeDuration);
    }

    this._onSpaceshipFreeze = function (time, freezeDuration) { };


    this.getNetPerformance = function (time) {
        return {
            netScore: 5,
            netTime: undefined,
            totalTime: undefined,
            score: undefined
        }
    }

    this.getNetTime = function (time) {
        return time - (this.startTime + this.freezeTime);
    }

  

   

}
PerformanceCalculatorInterface.prototype = new GameEventListener();

function LastSessionPerformanceCalculator() {

    this.startTime = 0;
    this.freezeTime = 0;

    this.score = 0;
    this.prevPerformanceData = {
        netScore: 18,
        netTime: 0,
        totalTime: 0,
        score: 0
    };

    this.shutdownScore = getNewScenario().meteorScore;
    this.collisionCost = getNewScenario().hitByMeteorScore;



    this.getNetPerformance = function (time) {
        netTime = this.getNetTime(time);
        if (netTime < 5000) {
            return this.prevPerformanceData;
        }
        netScore = this.getNetScore(netTime);
        duration = time - this.startTime;
        return {
            netScore: netScore,
            netTime: netTime,
            totalTime: duration,
            score: this.score
        }
    }

    this.getNetScore = function (netTime) {
        return this.score / (netTime / 1000);
    }

    this.getNetTime = function (time) {
        return time - (this.startTime + this.freezeTime);
    }

    this.onAction = function (time, action, mc) {
        switch (action){
            case enumAction.MAINTENANCE:
            case enumAction.MALFUNCTION_OCCUR:
                perfData = 
                this.prevPerformanceData = this.getNetPerformance(time);
                console.log("perData", perfData);
                this.startTime = time;
                this.freezeTime = 0;
                this.score = 0;
                break;
            case enumAction.SHUTDOWN:
            case enumAction.COLISSION:
                this.onCollisionOrShutdown(time, action);
                
        }
    }

    this.onCollisionOrShutdown = function(time, action){
        switch (action) {
            case enumAction.SHUTDOWN:
                this.score += this.shutdownScore; break;
            case enumAction.COLISSION:
                this.score -= this.collisionCost; break;
        }
    }

    this.onSpaceshipFreeze = function (time, freezeDuration) {
        this.freezeTime += freezeDuration; // when change this method, please change the overide method in LastTimeSegmentPerformanceCalculator
    }

    this.onRefuel = function (time, refuelCost) {
        this.score -= refuelCost;
    }

    this.onMalfunction = function (time, malfunction) { }
}
LastSessionPerformanceCalculator.prototype = new PerformanceCalculatorInterface();


function LastTimeSegmentPerformanceCalculator(segmentLength, shutdownScore, collisionCost) {

    this.defaultNetScore = 18; //scores per activity second game.
    this.bucketSize = 500; // in millisec
    this.secondScaler = 1000 / this.bucketSize;

    this.shutdownScore = shutdownScore;
    this.collisionCost = collisionCost;

    
    this.segmentLength = segmentLength;
    this.numOfBuckets = this.segmentLength / this.bucketSize;
    this.segmentScores = 0;
    
    this.startTimeBucket = 0;
    this.bucketScore = 0;   
    
    this.buckets = [];

    this.onCollisionOrShutdown = function (time, action, mc) {
        if (action != enumAction.SHUTDOWN && action != enumAction.COLISSION) {
            return;
        }
        this.createNewBucketIfNeed(time);

        switch (action) {
            case enumAction.SHUTDOWN: this.bucketScore += this.shutdownScore; break;
            case enumAction.COLISSION: this.bucketScore -= this.collisionCost; break;
        }
    }

    this.createNewBucketIfNeed = function (time) {
        var startTimeOfNextBucket = this.startTimeBucket + this.bucketSize;

        while (startTimeOfNextBucket <= time) {
            this.addNewBucket(startTimeOfNextBucket);
            startTimeOfNextBucket += this.bucketSize;
        }
    }

    this.addNewBucket = function (time) {
        // 1. add a current bucket
        this.buckets.push(this.bucketScore);
        this.segmentScores += this.bucketScore;

        // 2. remove score of first bucket (if needed).
        if (this.buckets.length > this.numOfBuckets) {
            var removedScores = this.buckets.shift();
            this.segmentScores -= removedScores;
        }

        // 3. init a new bucket
        this.startTimeBucket = time;
        this.bucketScore = 0;
    }

    this._onSpaceshipFreeze = function (time, freezeDuration) {
        this.startTimeBucket += freezeDuration;
    }

    this.getNetPerformance = function (time) {
        var netScore = this.defaultNetScore;
        if (this.buckets.length > 5) {
            netScore = (this.segmentScores / this.buckets.length) * this.secondScaler;
        }
        
        return {
            netScore: netScore,
            netTime: this.getNetTime(time),
            totalTime: undefined,
            score: undefined
        } 
    }
}
LastTimeSegmentPerformanceCalculator.prototype = new PerformanceCalculatorInterface();

function DiscountFactorPerformanceCalculator(initialPerformance, factor, shutdownScore, collisionCost) {

    this.calculatedPerformance = initialPerformance;
    this.factor = factor;
    this.shutdownScore = shutdownScore;
    this.collisionCost = collisionCost;

    this.bucketStartTime = 0;
    this.scores = 0;

    this.onCollisionOrShutdown = function (time, action, mc) {
        if (action != enumAction.SHUTDOWN && action != enumAction.COLISSION) {
            return;
        }
        
        if (time - this.bucketStartTime >= 1000) {
            this.calculatedPerformance = (this.factor * this.calculatedPerformance) + (1 - this.factor) * this.scores;
            this.bucketStartTime = time;
            this.scores = 0;
        }


        switch (action) {
            case enumAction.SHUTDOWN: this.scores += this.shutdownScore; break;
            case enumAction.COLISSION: this.scores -= this.collisionCost; break;
        }
    }

   

    this._onSpaceshipFreeze = function (time, freezeDuration) {
        this.bucketStartTime += freezeDuration;
    }

    this.getNetPerformance = function (time) {
        return {
            netScore: this.calculatedPerformance,
            netTime: this.getNetTime(time),
            totalTime: undefined,
            score: undefined
        }
    }
}
DiscountFactorPerformanceCalculator.prototype = new PerformanceCalculatorInterface();
